package ru.java2e;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.Timer;

public class Map extends JPanel implements ActionListener
{
	public class Cell
	{
		boolean empty;
		int brick;
		boolean concrete;
		boolean water;
		boolean tank;
		
		public Cell()
		{
			empty = true;
			brick = 0;
			concrete = false;
			water = false;
			tank = false;
		}
	}

	int test = 0;
	
	boolean blockMove = false;
	boolean gameOver = false;
	boolean gameStart = false;
	static boolean autoFire = false;
	int autoFireCombinationKey = 0;
	int kills = 0;
	int numbofbots = 10;
	
	Tank player;
	Tank[] units = new Tank[numbofbots];
	
	Cell world[][];
	int mapSize = 18;
	static int sizeCell = 32;
	
	Timer startTimer = new Timer(5000, this);
	Timer endTimer = new Timer(5000, this);
	Timer bulletTimer = new Timer(10, this);
	Timer botsTimer = new Timer(350, this);
	
	public Image imgBrick, imgBrick1Fire, imgBrick2Fire, imgBrick3Fire, imgConcrete, imgWater, imgPlayerTankUp, 
	imgPlayerTankLeft, imgPlayerTankDown, imgPlayerTankRight, imgBullet, imgBotTankUp, 
	imgBotTankRight, imgBotTankDown, imgBotTankLeft, imgHeadImage, imgGameOver, imgWin;
	
	Image[] imgExplosions;
	
	public Map()
	{
		addKeyListener(new AL());
		setFocusable(true);
		
		setBackground(Color.BLACK);
		
		ImageIcon ii_brick = new ImageIcon("res/brick.png");
		ImageIcon ii_brick1Fire = new ImageIcon("res/brick1Fire.png");
		ImageIcon ii_brick2Fire = new ImageIcon("res/brick2Fire.png");
		ImageIcon ii_brick3Fire = new ImageIcon("res/brick3Fire.png");
		ImageIcon ii_concrete = new ImageIcon("res/concrete.png");
		ImageIcon ii_water = new ImageIcon("res/water.png");
		ImageIcon ii_playerU = new ImageIcon("res/player-u.png");
		ImageIcon ii_playerR = new ImageIcon("res/player-r.png");
		ImageIcon ii_playerD = new ImageIcon("res/player-d.png");
		ImageIcon ii_playerL = new ImageIcon("res/player-l.png");
		ImageIcon ii_botU = new ImageIcon("res/bot-u.png");
		ImageIcon ii_botR = new ImageIcon("res/bot-r.png");
		ImageIcon ii_botD = new ImageIcon("res/bot-d.png");
		ImageIcon ii_botL = new ImageIcon("res/bot-l.png");
		ImageIcon ii_bullet = new ImageIcon("res/bullet.png");
		ImageIcon ii_gameover = new ImageIcon("res/game-over.png");
		ImageIcon ii_headimage = new ImageIcon("res/head_image.png");
		ImageIcon ii_winimage = new ImageIcon("res/win_image.png");
		ImageIcon ii_explosion1 = new ImageIcon("res/explosion1.png");
		ImageIcon ii_explosion2 = new ImageIcon("res/explosion2.png");
		ImageIcon ii_explosion3 = new ImageIcon("res/explosion3.png");
		ImageIcon ii_explosion4 = new ImageIcon("res/explosion4.png");
		ImageIcon ii_explosion5 = new ImageIcon("res/explosion5.png");
		ImageIcon ii_explosion6 = new ImageIcon("res/explosion6.png");
		imgBrick = ii_brick.getImage();
		imgBrick1Fire = ii_brick1Fire.getImage();
		imgBrick2Fire = ii_brick2Fire.getImage();
		imgBrick3Fire = ii_brick3Fire.getImage();
		imgConcrete = ii_concrete.getImage();
		imgWater = ii_water.getImage();
		imgPlayerTankUp = ii_playerU.getImage();
		imgPlayerTankRight = ii_playerR.getImage();
		imgPlayerTankDown = ii_playerD.getImage();
		imgPlayerTankLeft = ii_playerL.getImage();
		imgBotTankUp = ii_botU.getImage();
		imgBotTankRight = ii_botR.getImage();
		imgBotTankDown = ii_botD.getImage();
		imgBotTankLeft = ii_botL.getImage();
		imgBullet = ii_bullet.getImage();
		imgGameOver = ii_gameover.getImage();
		imgHeadImage = ii_headimage.getImage();
		imgWin = ii_winimage.getImage();
		imgExplosions = new Image[6];
		imgExplosions[0] = ii_explosion1.getImage();
		imgExplosions[1] = ii_explosion2.getImage();
		imgExplosions[2] = ii_explosion3.getImage();
		imgExplosions[3] = ii_explosion4.getImage();
		imgExplosions[4] = ii_explosion5.getImage();
		imgExplosions[5] = ii_explosion6.getImage();
		
		initWorld();
		
		player = createTank(10, 10, imgPlayerTankUp, imgPlayerTankRight, imgPlayerTankDown, imgPlayerTankLeft);
		player.setGroup(UnitGroup.PlayerGroup);
		player.setHP(100);
		units[0] = player;
		
		for(int k = 1; k < units.length; k++)
		{
			int x = (int) (Math.random()*mapSize);
			int y = (int) (Math.random()*mapSize);
			units[k] = createTank(x, y, imgBotTankUp, imgBotTankRight, imgBotTankDown, imgBotTankLeft);
			if(units[k] == null)
			{
				k--;
				continue;
			}
			units[k].setGroup(UnitGroup.BotGroup);
			units[k].setHP(200);
		}
		
		for(int y = 0; y < mapSize; y++)
			for(int x = 0; x < mapSize; x++)
			{
				if(!isTank(x, y))
				{
					int num = (int) (Math.random()*100 + 1);
					if(num < 30)
						setBrick(x, y);
					if(num > 80 && num < 90)
						setConcrete(x, y);
					if(num > 40 && num < 50)
						setWater(x, y);
				}
			}
		
		startTimer.start();
		bulletTimer.start();
		botsTimer.start();
	}
	
	private void initWorld()
	{
		world = new Cell[mapSize][mapSize];
		
		for(int y = 0; y < mapSize; y++)
			for(int x = 0; x < mapSize; x++)
				world[x][y] = new Cell();
	}

	private Tank createTank(int x, int y, Image imgUp, Image imgRight, Image imgDown, Image imgLeft)
	{
		Tank tank = new Tank(x, y);
		tank.setTankImages(imgUp, imgRight, imgDown, imgLeft);
		if(setTank(x, y, tank))
			return tank;
		return null;
	}

	private boolean setTank(int x, int y, Tank tank)
	{
		if(world[x][y].empty == true)
		{
			world[x][y].tank = true;
			world[x][y].empty = false;
			tank.setLocTank(x, y);
			return true;
		}
		return false;
	}
	
	private boolean setBrick(int x, int y)
	{
		if(world[x][y].empty == true)
		{
			world[x][y].brick = 1;
			world[x][y].empty = false;
			return true;
		}
		else if(world[x][y].brick > 0)
		{
			if(world[x][y].brick < 4)
				world[x][y].brick++;
			else
			{
				world[x][y].brick = 0;
				world[x][y].empty = true;
			}
			return true;
		}
		return false;
	}
	
	private boolean setConcrete(int x, int y)
	{
		if(world[x][y].empty == true)
		{
			world[x][y].concrete = true;
			world[x][y].empty = false;
			return true;			
		}
		return false;
	}

	private boolean setWater(int x, int y)
	{
		if(world[x][y].empty == true)
		{
			world[x][y].water = true;
			world[x][y].empty = false;
			return true;
		}
		return false;
	}
	
//	private boolean isEmpty(int x, int y)
//	{
//		if((x >= 0 && x < mapSize) && (y >= 0 && y < mapSize))
//			if(world[x][y].empty == true)
//				return true;
//		return false;
//	}
	
	private int isBrick(int x, int y)
	{
		if((x >= 0 && x < mapSize) && (y >= 0 && y < mapSize))
			return world[x][y].brick;
		return 0;
	}
	
	private boolean isConcrete(int x, int y)
	{
		if((x >= 0 && x < mapSize) && (y >= 0 && y < mapSize))
			if(world[x][y].empty == false)
				if(world[x][y].concrete == true)
					return true;
		return false;
	}
	
	private boolean isWater(int x, int y)
	{
		if((x >= 0 && x < mapSize) && (y >= 0 && y < mapSize))
			if(world[x][y].empty == false)
				if(world[x][y].water == true)
					return true;
		return false;
	}

	private boolean isTank(int x, int y)
	{
		if((x >= 0 && x < mapSize) && (y >= 0 && y < mapSize))
			if(world[x][y].empty == false)
				if(world[x][y].tank == true)
					return true;
		return false;
	}

	private boolean clearTank(int x, int y)
	{
		if(world[x][y].empty == false)
			if(world[x][y].tank == true)
			{
				world[x][y].tank = false;
				world[x][y].empty = true;
				return true;
			}
		return false;
	}
	
	public void actionPerformed(ActionEvent e)
	{
		if(e.getSource() == endTimer)
			gameOver = true;
		else if(e.getSource() == startTimer)
		{
			if(!gameStart)
			{
				gameStart = true;
				startTimer.stop();
			}
		}
		else if(e.getSource() == bulletTimer)
		{
			if(!gameOver && gameStart)
			{
				for(int k = 0; k < units.length; k++)
				{
					units[k].moveAllBullet();
					Bullet bullets[] = units[k].getArrayBullets();
					
					for(int i = 0; i < bullets.length; i++)
					{
						int x = bullets[i].x/sizeCell;
						int y = bullets[i].y/sizeCell;
						if(x < 0 || x > mapSize || y < 0 || y > mapSize || isConcrete(x, y) || isBrick(x, y) > 0 || isTank(x, y))
						{
							if(isTank(x, y))
							{
								Tank receiver = null;
								Tank sender = bullets[i].getSender();
								
								for(Tank tank: units)
									if (tank.getX() == x && tank.getY() == y)
									{
										receiver = tank;
										break;
									}
								
								if(sender != receiver)
								{
									if(sender.getGroup() != receiver.getGroup())
										if(receiver.takeDamage(100))
										{
											receiver.explosionLvl = 1;
											
											clearTank(x, y);
											kills++;
											if(receiver.getGroup() == UnitGroup.PlayerGroup)
											{
												clearTank(x, y);
												kills--;
												endTimer.start();
												blockMove = true;
											}
										}
									
									units[k].deleteBullet(i);
									bullets = units[k].getArrayBullets();
									i = 0;
								}
							}
							else
							{
								if(isBrick(x, y) > 0)
									setBrick(x, y);
								
								units[k].deleteBullet(i);
								bullets = units[k].getArrayBullets();
								i = 0;
							}
						}
					}	
				}
			}
		}	
		else if(e.getSource() == botsTimer)
		{
			moveBot();
			fireBot();
		}
		repaint();
	}

	public void paint(Graphics g)
	{
		super.paint(g);
		Graphics2D g2 = (Graphics2D) g;
		if(gameStart)
		{
			if(!gameOver)
			{
				if(kills != numbofbots-1)
				{		
					for(int y = 0; y < mapSize; y++)
					{
						for(int x = 0; x < mapSize; x++)
						{
							if(isBrick(x, y) == 1)
								g2.drawImage(imgBrick, x*sizeCell, y*sizeCell, null);
							else if(isBrick(x, y) == 2)
								g2.drawImage(imgBrick1Fire, x*sizeCell, y*sizeCell, null);
							else if(isBrick(x, y) == 3)
								g2.drawImage(imgBrick2Fire, x*sizeCell, y*sizeCell, null);
							else if(isBrick(x, y) == 4)
								g2.drawImage(imgBrick3Fire, x*sizeCell, y*sizeCell, null);
							
							if(isConcrete(x, y))
								g2.drawImage(imgConcrete, x*sizeCell, y*sizeCell, null);
							if(isWater(x, y))
								g2.drawImage(imgWater, x*sizeCell, y*sizeCell, null);
						}
					}
						
					for(int k = 0; k < units.length; k++)
					{
						Bullet bullets[] = units[k].getArrayBullets();
						
						for(int l = 0; l < bullets.length; l++)
						{
							ImageIcon icon = new ImageIcon(imgBullet);
							int x = bullets[l].x - icon.getIconWidth()/2;
							int y = bullets[l].y - icon.getIconHeight()/2;
							g2.drawImage(imgBullet, x, y, null);
						}			
					}
					
					for(int k = 0; k < units.length; k++)
						if(units[k].getHP() > 0)
							g2.drawImage(units[k].getTankImage(), units[k].getX()*sizeCell, units[k].getY()*sizeCell, null);
						else if(units[k].explosionLvl != 0)
						{
							g2.drawImage(imgExplosions[units[k].explosionLvl - 1],units[k].getX()*sizeCell, units[k].getY()*sizeCell, null);
							units[k].explosionLvl++;
							if(units[k].explosionLvl > 6)
								units[k].explosionLvl = 0;
						}
					
					g2.setColor(Color.RED);
					for(int y = 0; y < mapSize; y++)
						for(int x = 0; x < mapSize; x++)
							if(isTank(x, y))
								g2.drawOval(x*sizeCell+sizeCell/2, y*sizeCell+sizeCell/2, 3, 3);
					
				
					}
					else
						g2.drawImage(imgWin, 0, 0, null);
				}
				else
					g2.drawImage(imgGameOver, 0, 0, null);
			}
			else
				g2.drawImage(imgHeadImage, 0, 0, null);		
		}
	
	private void moveBot()
	{
		for(int k = 1; k < units.length; k++)
		{
			if(units[k].getHP() > 0)
			{
				int botX = units[k].getX();
				int botY = units[k].getY();
				
				int exitX = botX;
				int exitY = botY;
				
				if(units[k].getDirectTank() == Direction.Up)
					exitY--;
				else if(units[k].getDirectTank() == Direction.Right)
					exitX++;
				else if(units[k].getDirectTank() == Direction.Down)
					exitY++;
				else if(units[k].getDirectTank() == Direction.Left)
					exitX--;
				
				if(exitX != botX || exitY != botY)
			        if(exitX >= 0 && exitX <= mapSize-1)
			        	if(exitY >= 0 && exitY <= mapSize-1)
			        	{
			        		clearTank(botX, botY);
			        		if(isBrick(exitX, exitY) == 0 && !isConcrete(exitX, exitY) && !isWater(exitX, exitY) && !isTank(exitX, exitY))
	        					setTank(exitX, exitY, units[k]);
			        		else
			        		{
			        			setTank(botX, botY, units[k]);
			        			units[k].percentTurnTank();
			        		}

			        	}
				
				int percentTurn = (int) (Math.random()*100);
				
				if(percentTurn < 10)
					units[k].percentTurnTank();
				
		        repaint();
			}
		}
	}
	
	private void fireBot()
	{
		int procent = (int)(Math.random()*100);
		if(procent < 32)
		{
			bulletTimer.start();
			for(int k = 1; k < units.length; k++)
				if(units[k].getHP() > 0)
					units[k].fire();
		}
	}
	
	private class AL extends KeyAdapter
	{	
		public void keyPressed(KeyEvent e)
		{
			int tankX = player.getX();
			int tankY = player.getY();
			
			int exitX = tankX;
			int exitY = tankY;
			
			int key = e.getKeyCode();
			System.out.println("Key: " + key);
			
			if(!blockMove)
			{
			if (key == KeyEvent.VK_SPACE)
				player.fire();
			else if (key == KeyEvent.VK_UP || key == KeyEvent.VK_W)
	        {
	        	if(player.getDirectTank() != Direction.Up)
	        		player.setDirectTank(Direction.Up);
	        	else
	        		exitY--;
	        }
			else if (key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_D)
	        {
	        	if(player.getDirectTank() != Direction.Right)
	        		player.setDirectTank(Direction.Right);
	        	else
	        		exitX++;
	        }
			else if (key == KeyEvent.VK_DOWN || key == KeyEvent.VK_S)
	        {
	        	if(player.getDirectTank() != Direction.Down)
	        		player.setDirectTank(Direction.Down);
	        	else
	        		exitY++;
	        }
			else if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_A)
	        {
	        	if(player.getDirectTank() != Direction.Left)
	        		player.setDirectTank(Direction.Left);
	        	else
	        		exitX--;
	        }
			else if(key == KeyEvent.VK_CONTROL && autoFireCombinationKey == 0)
				autoFireCombinationKey = 1;
			else if(key == KeyEvent.VK_SHIFT && autoFireCombinationKey == 1)
				autoFireCombinationKey = 2;
			else if(key == KeyEvent.VK_BACK_SPACE && autoFireCombinationKey == 2)
			{
				System.out.println("Test");
				autoFire = !autoFire;
			}
			else
				autoFireCombinationKey = 0;
	        
	        if(exitX != tankX || exitY != tankY)
		        if(exitX >= 0 && exitX <= mapSize-1)
		        	if(exitY >= 0 && exitY <= mapSize-1)
		        	{
		        		clearTank(tankX, tankY);
		        		if(isBrick(exitX, exitY) == 0 && !isConcrete(exitX, exitY) && !isWater(exitX, exitY) && !isTank(exitX, exitY))
        					setTank(exitX, exitY, player);
		        		else
		        			setTank(tankX, tankY, player);
		        	}
	        
	        repaint();
		}
	}
}
}